package org.huwei.data.manager;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 	数据源操作工具
 * @author huwei
 *
 */
public class DataSourceUtil {
	
	static private Map<Class<?> ,DataSourceManager<?>> dataSourceManagerMap = new ConcurrentHashMap<Class<?> ,DataSourceManager<?>>();

	/**
	 * 	获取(1)指定接口的数据源管理对象中(2)指定数据源实现类的下一个可操作数据源对象；
	 * 	解释：
	 * 	1，指定接口-superClass ：该参数所表示的类类型为{@link DataSourceManagerFacotryProperties#getDataSourceInterfacePackagePath()} 所定义的包路径下的接口的类类型；
	 * 	2，指定数据源实现类-cls ：该参数所表示的类类型为实现了superClass的某一个类的类类型，且该类的对象被加载到spring容器中；
	 * 	返回值：
	 * 	当指定的cls参数的后面有可用的数据源则返回该数据源的操作对象{@link DataSourceOperation} ，而这里指的后面：是依据实现对象所定义的优先级所决定的；
	 * 	当指定的cls参数的后面无可用数据源，或dsmf 、superClass 、cls等不可用时，则返回空；
	 * @param dsmf 数据源管理器制造工厂
	 * @param superClass  该参数所表示的类类型为{@link DataSourceManagerFacotryProperties#getDataSourceInterfacePackagePath()} 所定义的包路径下的接口的类类型；
	 * @param cls 该参数所表示的类类型为实现了superClass的某一个类的类类型，且该类的对象被加载到spring容器中；
	 * @return 数据源操作对象，也可能为空
	 */
	static public<T> DataSourceOperation next(Class<T> superClass ,Class<? extends T> cls) {
		@SuppressWarnings("unchecked")
		DataSourceManager<T> dsm = (DataSourceManager<T>) dataSourceManagerMap.get(superClass);
		return dsm == null ? null : dsm.next(cls);
	}
	
	/**
	 * 	获取(1)指定接口的数据源管理对象中(2)指定数据源实现类的下一个可操作数据源对象，并调用该可用数据源的当前方法；
	 * 	解释：
	 * 	1和2，请参考 {@link #next(DataSourceManagerFacotry, Class, Class)} 方法解释；
	 * 	返回值：
	 * 	当存在可操作数据源对象时，返回值为当前数据源(1)当前方法的返回值；反之，为空；
	 * 	返回值解析：
	 * 	1，当前方法： 调用{@link #invokeMethodByNextDataSource(DataSourceManagerFacotry, Class, Class)} 时，需要调用者为参数superClass的实现类；
	 * @param superClass  该参数所表示的类类型为{@link DataSourceManagerFacotryProperties#getDataSourceInterfacePackagePath()} 所定义的包路径下的接口的类类型；
	 * @param cls 该参数所表示的类类型为实现了superClass的某一个类的类类型，且该类的对象被加载到spring容器中；
	 * @return 当前调用方法的执行结果，或无可操作对象时，返回空；所以空值具有多层含义需要用户自行判断；
	 */
	static public<T> Object invokeMethodByNextDataSource(Class<T> superClass ,Class<? extends T> cls) {
		DataSourceOperation dso = next(superClass, cls);
		if(Objects.nonNull(dso)) {
			return dso.invokeCurrentMethod();
		}
		return null;
	}
	
	static void addManager(Map<Class<?> ,DataSourceManager<?>> map) {
		dataSourceManagerMap.putAll(map);
	}
}
